﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace Heaven.Engine.Concurrency
{
    /// <summary>
    /// Front-end interface of a collection
    /// </summary>
    public class GenericCollection<T> : IEnumerable<T>
    {
        #region Events

        /// <summary>
        /// The event of an item addition
        /// </summary>
        public event CollectionItemDelegate<T> Added;

        /// <summary>
        /// The event of an item removing
        /// </summary>
        public event CollectionItemDelegate<T> Removed;

        /// <summary>
        /// Occurs when the collection has been changed
        /// </summary>
        public event EventHandler Invalidated;

        #endregion

        #region Fields

        // Items of the collection
        List<T> items = new List<T>();

        #endregion

        #region Properties

        /// <summary>
        /// The number of elements
        /// </summary>
        public int Count
        {
            get { return items.Count; }
        }

        /// <summary>
        /// Indexer
        /// </summary>
        /// <param name="i">Index</param>
        /// <returns>Item</returns>
        public T this[int i]
        {
            get { return items[i]; }
            set { items[i] = value; }
        }

        #endregion

        #region Initialization

        /// <summary>
        /// Default constructor
        /// </summary>
        public GenericCollection()
        { }

        #endregion

        #region Methods

        /// <summary>
        /// Adds an item
        /// </summary>
        /// <param name="item"></param>
        public virtual void Add(T item)
        {
            items.Add(item);
            if (Added != null) Added(this, new CollectionItemArgs<T>(item));
            if (Invalidated != null) Invalidated(this, EventArgs.Empty);
        }

        /// <summary>
        /// Adds a range of items
        /// </summary>
        /// <param name="newitems">Items</param>
        public void AddRange(IEnumerable<T> newitems)
        {
            foreach (T item in newitems)
            {
                Add(item);
            }
        }

        /// <summary>
        /// Removes the given item
        /// </summary>
        /// <param name="item"></param>
        public virtual void Remove(T item)
        {
            items.Remove(item);
            if (Removed != null) Removed(this, new CollectionItemArgs<T>(item));
            if (Invalidated != null) Invalidated(this, EventArgs.Empty);
        }

        /// <summary>
        /// Removes an item with the given index
        /// </summary>
        /// <param name="index">Index of an item</param>
        public void RemoveAt(int index)
        {
            Remove(items[index]);
        }

        /// <summary>
        /// Determines whether the element is in the collection
        /// </summary>
        /// <param name="item">The item</param>
        /// <returns>True if the item is found in 
        /// the collection; otherwise, false</returns>
        public bool Contains(T item)
        {
            return items.Contains(item);
        }

        /// <summary>
        /// Gets index of the given item
        /// </summary>
        /// <param name="item">An item</param>
        /// <returns>Index of the item</returns>
        public int GetIndexOf(T item)
        {
            return items.IndexOf(item);
        }

        /// <summary>
        /// Copies the elements of the collection to a new array
        /// </summary>
        /// <returns>Array</returns>
        public T[] ToArray()
        {
            return items.ToArray();
        }

        /// <summary>
        /// Invalidates object
        /// </summary>
        public void Invalidate()
        {
            if (Invalidated != null) Invalidated(this, EventArgs.Empty);
        }

        /// <summary>
        /// Removes all elements
        /// </summary>
        public void Clear()
        {
            for (int i = items.Count - 1; i >= 0; i--)
            {
                Remove(items[i]);
            }
        }

        #endregion

        #region Enumerating

        /// <summary>
        /// Returns an enumerator that iterates through the collection
        /// </summary>
        /// <returns>A System.Collections.Generic.IEnumerator 
        /// that can be used to iterate through the collection</returns>
        public IEnumerator<T> GetEnumerator()
        {
            return items.GetEnumerator();
        }


        /// <summary>
        /// Returns an enumerator that iterates through the collection
        /// </summary>
        /// <returns>A System.Collections.Generic.IEnumerator 
        /// that can be used to iterate through the collection</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return items.GetEnumerator();
        }

        #endregion
    }

    /// <summary>
    /// This is a class of an argument of the delegate
    /// </summary>
    /// <typeparam name="T">Type of items of collection</typeparam>
    public class CollectionItemArgs<T> : EventArgs
    {
        /// <summary>
        /// Related item
        /// </summary>
        public readonly T Item;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="item">The item</param>
        public CollectionItemArgs(T item)
        {
            Item = item;
        }
    }

    /// <summary>
    /// A delegate is where item of a generic collection participate
    /// </summary>
    /// <param name="sender">Sender</param>
    /// <param name="args">Argument</param>
    public delegate void CollectionItemDelegate<T>(object sender, CollectionItemArgs<T> args);
}
